package piwan;

import java.io.IOException;
//import java.util.ArrayList;
//import java.util.HashMap;
import java.util.Scanner;

import javax.media.opengl.GL;

public class Polygon {
	public Polygon() {}
	/*
	private Polygon(ArrayList<Vector2> fromVerts) {
		setFromVerts(fromVerts);
	}*/
	/*
	private void setFromVerts(ArrayList<Vector2> fromVerts) {
		verts = new Vector2[fromVerts.size()];
		int i=0;
		for(Vector2 v: fromVerts) verts[i++] = v;
		computeCentroid();
		computeNormals();
	}
	*/
	public Vector2[] getVertices() { return verts; }
	
	public void readFromMap(Scanner file, World w) throws IOException {
		int nv = file.nextInt();
		verts = new Vector2[nv];
		for(int i=0; i<nv; ++i)
			verts[i] = w.getVertex(file.nextInt());
		computeCentroid();
		computeNormals();
	}
	
	public Polygon[] breakIslands() {
		/*
		ArrayList< ArrayList<Vector2> > islands = new ArrayList<ArrayList<Vector2>>();
		HashMap<Vector2,Integer> visited = new HashMap<Vector2, Integer>();
		ArrayList<Vector2> bisl = new ArrayList<Vector2>();
		islands.add( bisl );
		for(int i=0; i<verts.length; ++i)
			bisl.add(verts[i]);
		boolean broken,rmend;
		do {
			visited.clear();
			broken = false;
			for(int i=0;i<bisl.size();++i) {
				Integer start = visited.get(bisl.get(i));
				if( start!=null ) {
					rmend = false;
					if(i<bisl.size()-1 && visited.get(bisl.get(i+1))!=null )
						rmend = true;
					
					
					int end = i;
					ArrayList<Vector2> nisl = new ArrayList<Vector2>();
					islands.add(nisl);
					for(int j=start;j<end;++j)
						nisl.add(bisl.remove(start.intValue()));
					if(rmend) {
						bisl.remove(start.intValue());
						bisl.remove(start.intValue());
					}
					broken = true;
					break;
				} else
					visited.put(bisl.get(i), i);
			}
		} while(broken);
		
		
		Polygon[] ret = new Polygon[islands.size()];
		setFromVerts(bisl);
		ret[0] = this;
		
		for(int i=1;i<ret.length;++i)
			ret[i] = new Polygon(islands.get(i)); 
		*/
		return new Polygon[] {this};
	}
	
	public boolean contains( Vector2 v ) {
		int i, ps = verts.length, j =ps-1;
		boolean oddNodes = false;
		if( ps < 3 ) return false;
		for(i=0;i<ps;++i) {
			 Vector2 vi = verts[i];
			 Vector2 vj = verts[j];
			 if(vi.y<v.y && vj.y >= v.y || vj.y<v.y && vi.y>=v.y) {
				 if( vi.x + (v.y-vi.y)/(vj.y-vi.y) * (vj.x-vi.x) < v.x ) {
					 oddNodes = !oddNodes;
				 }
			 }
			 j=i;
		}
		
		return oddNodes;
	}
	
	public double getArea() { return area; }
	public Vector2 getCentroid() { return centroid; }
	
	private void computeCentroid() {
		double cx = 0.0;
		double cy = 0.0;
		double term;
		int imax = verts.length-1;
		
		for(int i=0;i<imax;++i) {
			term = verts[i].x*verts[i+1].y - verts[i+1].x*verts[i].y;
			area += term;
			cx += (verts[i].x + verts[i+1].x)*term;
			cy += (verts[i].y + verts[i+1].y)*term;
		}
		
		term = verts[imax].x*verts[0].y - verts[0].x*verts[imax].y;
		area += term;
		cx += (verts[imax].x + verts[0].x)*term;
		cy += (verts[imax].y + verts[0].y)*term;
		
		area /= 2.0;
		
		cx /= 6.0*area;
		cy /= 6.0*area;
		if( area<0 ) area=-area;
		centroid.set(cx,cy);
	}
	
	public void lineRender(GL gl, double y) {
		gl.glLineWidth(4.0f);
		gl.glBegin(GL.GL_LINE_LOOP);
		for(Vector2 v: verts)
			gl.glVertex3d(v.x,y,v.y);
		gl.glEnd();
		gl.glBegin(GL.GL_LINES);
		Vector2 a = new Vector2(),b = new Vector2();
		for(int i=0;i<verts.length;++i) {
			comp(i,0.01,a,b);
			gl.glVertex3d(a.x,y,a.y);
			gl.glVertex3d(b.x,y,b.y);
		}
		gl.glEnd();
	}
	
	public void normRender(GL gl, double y) {
	}
	
	private void comp(int i, double w, Vector2 a, Vector2 b) {
		a.set(verts[i]);
		b.set(a).add(norms[i].times(w));
	}
	
	public void quadRender(GL gl, double y, double w) {
		
		Vector2 al=new Vector2(),bl=new Vector2(),ai=new Vector2(),bi=new Vector2();
		comp(verts.length-1,w,al,bl);
		for(int i=0; i<verts.length; ++i) {
			comp(i,w,ai,bi);
			gl.glTexCoord2d(0.0,0.0);
			gl.glVertex3d(al.x,y,al.y);
			gl.glTexCoord2d(0.0,1.0);
			gl.glVertex3d(ai.x,y,ai.y);
			gl.glTexCoord2d(1.0,1.0);
			gl.glVertex3d(bi.x,y,bi.y);
			gl.glTexCoord2d(1.0,0.0);
			gl.glVertex3d(bl.x,y,bl.y);
			al.set(ai);
			bl.set(bi);
		}
		
	}
	
	private void computeNormals() {
		int j = verts.length-1;
		int i;
		Vector2 vi,vj,vk;
		norms = new Vector2[verts.length];
		for(i=0;i<verts.length;++i) {
			vi = verts[i];
			vj = verts[j];
			vk = verts[(i+1)%verts.length];
			vj = vj.minus(vi).unit();
			vk = vk.minus(vi).unit();
			norms[i] = vj.plus(vk).unit();
			
			if( !contains(norms[i].times(.0001).plus(vi)) )
				norms[i].mul(-1.0);
			
			if(norms[i].x == 0.0 && norms[i].y == 0.0 ) {
				vi.x+=0.00000001;
				vi.y+=0.00000001;
				--i;
				continue;
			}
			j = i;
			
			
		}
	}
	
	private Vector2[] verts = null;
	private Vector2[] norms = null;
	private Vector2 centroid = new Vector2();
	private double area = 0.0;
}
